# src/dockerfile.py
import os
import glob
from jinja2 import Environment, FileSystemLoader

def _norm_path(p: str) -> str:
    """把路径统一成使用 / 的相对样式，避免 Windows 反斜杠进模板。"""
    return (p or "").replace("\\", "/")

def _guess_bin_name(rel_path: str) -> str:
    """
    兜底：若 analyzer 未提供 bin_name，则根据入口文件名推导：
      - main.go -> 取上级目录名（根目录则 app）
      - 其他 .go -> 去掉 .go
    """
    rel_path = _norm_path(rel_path)
    base = os.path.basename(rel_path)
    dir_rel = _norm_path(os.path.dirname(rel_path))
    if base == "main.go":
        return os.path.basename(dir_rel) if dir_rel not in ("", ".") else "app"
    if base.endswith(".go"):
        return base[:-3] or "app"
    return "app"

def _get_mode_config(build_mode: str) -> dict:
    """获取不同模式的配置"""
    configs = {
        "lightweight": {
            "base_image": "opencloudos/opencloudos9-minimal",
            "runtime_packages": ["ca-certificates"],  # 最小运行时包
            "build_flags": "-ldflags '-s -w'",  # 去除调试信息和符号表
            "include_docs": False,
            "include_shell": False,
            "user": "nobody",
            "strip_binary": True,
            "compress": True
        },
        "standard": {
            "base_image": "opencloudos/opencloudos9-minimal",
            "runtime_packages": ["ca-certificates", "tzdata"],
            "build_flags": "-ldflags '-s -w'",
            "include_docs": True,
            "include_shell": True,
            "user": "root",
            "strip_binary": False,
            "compress": False
        },
        "debug": {
            "base_image": "opencloudos/opencloudos9",  # 完整版本
            "runtime_packages": [
                "ca-certificates", "tzdata", "curl", "wget", 
                "strace", "gdb", "net-tools", "procps-ng",
                "vim-minimal", "less"
            ],
            "build_flags": "-gcflags='all=-N -l'",  # 保留调试信息
            "include_docs": True,
            "include_shell": True,
            "user": "root",
            "strip_binary": False,
            "compress": False,
            "extra_tools": True
        }
    }
    return configs.get(build_mode, configs["standard"])

def generate_dockerfile(project_info, context_dir, bin_entries=None, default_bin=None, build_mode="standard"):
    """
    生成 Dockerfile：
      - multi_bin=True 时，构建产物放在 /out/bin/<out_rel>/<bin_name>
      - 运行期 COPY 到 /app/<pname>/bin/，从而保留原有目录层级
      - 新增 build_mode 参数支持不同构建模式
    """
    # bin_entries 结构期望来自 analyzer.detect_all_entries，至少包含:
    #   { "name": <展示名>, "rel": "<dir>/main.go", "out_rel": "<dir>", "bin_name": "<可执行名>" }
    bin_entries = bin_entries or [{"name": "app", "rel": project_info["entry_rel"], "out_rel": "app", "bin_name": "app"}]
    # 允许 default_bin 仍沿用 out_rel 的含义（用作"默认启动"的相对路径标识）
    multi_bin = len(bin_entries) > 1
    default_bin = default_bin or bin_entries[0].get("out_rel", "app")

    project_root = project_info.get("go_path", "") or os.path.dirname(project_info.get("entry", ""))
    project_name = os.path.basename(project_root) or "app"

    # 收集 README（仅限项目根）
    readme_patterns = ["README.md", "README.MD", "README_*.md", "README.*.md", "README", "README.txt"]
    readmes = []
    for pat in readme_patterns:
        for p in glob.glob(os.path.join(project_root, pat)):
            if os.path.isfile(p):
                readmes.append(os.path.basename(p))
    seen = set()
    readmes = [x for x in readmes if not (x in seen or seen.add(x))]

    has_docs = os.path.isdir(os.path.join(project_root, "docs"))

    runtime_sys_packages = project_info.get("runtime_sys_packages", [])
    build_sys_packages = project_info.get("sys_packages_suggested", [])

    # ✅ 规范化每个入口：源码目录(dir)、输出目录(out_rel)、可执行名(bin_name)
    norm_bins = []
    for e in bin_entries:
        rel = _norm_path(e.get("rel", "main.go"))            # 例如 "cmd/caddy/main.go"
        src_dir = _norm_path(os.path.dirname(rel) or ".")    # 例如 "cmd/caddy"
        out_rel = _norm_path(e.get("out_rel", src_dir) or ".")
        bin_name = e.get("bin_name") or _guess_bin_name(rel)

        norm_bins.append({
            "name": e.get("name") or bin_name,   # 显示/探针时可用
            "rel": rel,                          # 源相对文件
            "dir": src_dir,                      # go build -C 用
            "out_rel": out_rel,                  # 输出目录层级（相对 /out/bin）
            "bin_name": bin_name,                # 最终二进制名
        })

    # 获取模式配置
    mode_config = _get_mode_config(build_mode)

    # 渲染模板
    tmpl_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "templates")
    env = Environment(
        loader=FileSystemLoader(tmpl_dir),
        autoescape=False,
        trim_blocks=True,
        lstrip_blocks=True,
    )
    template = env.get_template("dockerfile.j2")

    dockerfile_content = template.render(
        use_cgo=project_info.get("use_cgo", False),
        tools_detected=project_info.get("tools_detected", []),
        entry_rel=_norm_path(project_info.get("entry_rel", "main.go")),
        multi_bin=multi_bin,
        bin_entries=norm_bins,            # 提供 dir/out_rel/bin_name
        default_bin=default_bin,
        project_name=project_name,
        readmes=readmes,
        has_docs=has_docs,
        runtime_sys_packages=runtime_sys_packages,
        build_sys_packages=build_sys_packages,
        build_mode=project_info.get("build_mode"),
        installer_cmd=project_info.get("installer_cmd"),
        strip_sudo=project_info.get("strip_sudo", True),
        go_version=project_info.get("go_version", "1.20"),
        # 新增：构建模式相关
        build_mode_name=build_mode,
        mode_config=mode_config,
    )

    dockerfile_path = os.path.join(context_dir, "Dockerfile")
    with open(dockerfile_path, "w", encoding="utf-8") as f:
        f.write(dockerfile_content)

    return dockerfile_path, dockerfile_content